/*
 * INSANE - Interactive Structural Analysis Environment
 *
 * Copyright (C) 2003-2005
 * Universidade Federal de Minas Gerais
 * Escola de Engenharia
 * Departamento de Engenharia de Estruturas
 * 
 * Author's email :    insane@dees.ufmg.br
 * Author's website :  http://www.dees.ufmg.br/insane
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package br.ufmg.dees.insane.ui.rich.postp.postp_view.command;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ListIterator;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;

import br.ufmg.dees.insane.commons.command.Command;
import br.ufmg.dees.insane.commons.view.ExtensionFileFilter;
import br.ufmg.dees.insane.model.postp.Boundary;
import br.ufmg.dees.insane.model.postp.GeoPostpModel;
import br.ufmg.dees.insane.model.postp.Patch;
import br.ufmg.dees.insane.model.postp.PointModel;
import br.ufmg.dees.insane.model.postp.StepPostp;
import br.ufmg.dees.insane.ui.rich.postp.postp_view.DesktopPostp;
import br.ufmg.dees.insane.ui.rich.postp.postp_view.InterfacePostp;


/**
 * This class is an implementation of the interface Command.
 * its unabled to undo or redo.
 * its "execute" method encodes the current fem model as
 * a XML file in a given file.
 *
 * @author Penna, Samuel & Fonseca, Flavio & Pitangueira, Roque
 * @since 05/07/2006
 * @see gui.command.Command
 */
public class ExportXMLCommand implements Command {
	
	private DesktopPostp parent;
	private JFileChooser fileChooser = new JFileChooser();
	private ExtensionFileFilter filter = new ExtensionFileFilter(new String[]{"xml"}, "XML Files");
	private boolean validFile;
	
	/** The Model of this persistence. */
	protected static StepPostp stepPostp;
	
	/** The Object which will be serialized. */
	protected static Object docOutput;
	/**
	 * Creates new ExportXMLCommand
	 * and sets the FileFilter of FileChooser.
	 *
	 * @param parent The JFrame parent.
	 */
	public ExportXMLCommand(JFrame parent) {
		this.parent = (DesktopPostp)parent;
		fileChooser.setFileFilter(filter);
	}
	
//	*****************************************************************************
	
	/**
	 * Calls the file chooser an encode the fem model as a XML file.
	 *
	 * @see gui.command.Command#execute()
	 */
	public void execute() {
		
		validFile = false;
		while (!validFile) {
			
			fileChooser.setDialogTitle("Export XML");
			int retVal = fileChooser.showDialog(parent, "Export");
			if (retVal == JFileChooser.APPROVE_OPTION) {
				
				//Getting the file name
				String s = fileChooser.getSelectedFile().getName();
				
				//Getting the file extension
				String ext = new String();
				int i = s.lastIndexOf('.');
				if (i > 0 &&  i < s.length() - 1) {
					ext = s.substring(i+1).toLowerCase();
				}
				
				//Comparing the extension
				if (!ext.equals("xml")) {
					s = s + ".xml";
					File file = fileChooser.getSelectedFile();
					
					//Changing the file in case of no good extensions
					fileChooser.setSelectedFile(new File(file.getParent() + File.separator + s));
				}
				
				//Checks if the file exists
				if (fileChooser.getSelectedFile().exists()){
					int value = 10;
					value = JOptionPane.showConfirmDialog(parent,
							"File \"" + fileChooser.getSelectedFile().getPath() + "\" exists.\nDo you want to replace it?",
							"Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
					if (value == JOptionPane.YES_OPTION){
						validFile = true;
					}
				}
				else {
					validFile = true;
				}
			}
			else return;
		}
		try {
			
			stepPostp = ((InterfacePostp)parent.getDesktop().getSelectedFrame()).getModel();
			fillFileFromModel();
			serializeDOMTreeIntoXMLDocument(fileChooser.getSelectedFile()+"");
		} catch (NullPointerException e) {
			
		} catch (Exception e) {
			
		}
		validFile = false;
	}
	
//	*****************************************************************************
	
	/**
	 * Impossible to undo - not implemented.
	 */
	public void undo() {}
	
//	*****************************************************************************
	
	/**
	 * Impossible to redo - not implemented.
	 */
	public void redo() {}
	
	
//	*****************************************************************************
	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.persistence.Persistence#fillFileFromModel(java.lang.String)
	 */
	public void fillFileFromModel() {
		DocumentBuilder builder = null;
		try{
			builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		}catch(ParserConfigurationException pce){
			
		}
		
		Document doc = builder.newDocument();
		
		//Creating formator
		DecimalFormat fmt = new DecimalFormat();
		DecimalFormatSymbols fsym = new DecimalFormatSymbols();
		fsym.setDecimalSeparator('.');
		fmt.setDecimalFormatSymbols(fsym);
		
		//All the classes which will be instantiated are declared here
		PointModel point;
		Boundary boundary;
		Patch patch;
		
		//Creating root DOM element "PostpData"
		org.w3c.dom.Element root = doc.createElement("PostpData");
		doc.appendChild(root);
		
		//Creating DOM element "Step"
		org.w3c.dom.Element elemStep = doc.createElement("Step");
		elemStep.setAttribute("label", "" + stepPostp.getLabel());
		root.appendChild(elemStep);
		
		//Creating DOM element "GeoPostpModelList"
		org.w3c.dom.Element elemGeoPostpModelList = doc.createElement("GeoPostpModelList");
		elemStep.appendChild(elemGeoPostpModelList);
		
		//Creating DOM elements "GeoPostpModel"
		ListIterator geoPostpModelIT = stepPostp.getGeoPostpModelList().listIterator();
		
		while (geoPostpModelIT.hasNext()){
			GeoPostpModel geoPostpModel = (GeoPostpModel)geoPostpModelIT.next();
			
			//Creating DOM element "GeoPostpModel"
			org.w3c.dom.Element elemGeoPostpModel = doc.createElement("GeoPostpModel");
			elemGeoPostpModel.setAttribute("label", "" + geoPostpModel.getLabel());
			elemGeoPostpModelList.appendChild(elemGeoPostpModel);
			
			//Creating DOM element "PointsList"
			org.w3c.dom.Element elemPointsList = doc.createElement("PointsList");
			elemGeoPostpModel.appendChild(elemPointsList);
			
			//Creating DOM elements "PointModel"
			ListIterator pointsIT = geoPostpModel.getPoints().listIterator();
			while (pointsIT.hasNext()){
				point = (PointModel)pointsIT.next();
				
				org.w3c.dom.Element elemPointModel = doc.createElement("PointModel");
				elemPointModel.setAttribute("label", "" + point.getLabel());
				elemPointsList.appendChild(elemPointModel);
				
				//Creating DOM elements "Coord"
				org.w3c.dom.Element elemCoord = doc.createElement("Coord");
				fmt.applyPattern("0.0000E00");
				elemCoord.appendChild(doc.createTextNode(String.valueOf(fmt.format(point.getX()))));
				elemCoord.appendChild(doc.createTextNode(" "));
				elemCoord.appendChild(doc.createTextNode(String.valueOf(fmt.format(point.getY()))));
				elemCoord.appendChild(doc.createTextNode(" "));
				elemCoord.appendChild(doc.createTextNode(String.valueOf(fmt.format(point.getZ()))));
				elemPointModel.appendChild(elemCoord);
				
				//Creating DOM elements "value"
				for(int j=0;j<point.getValues().keySet().size();j++){
					org.w3c.dom.Element elemValue = doc.createElement("Value");
					elemValue.appendChild(doc.createTextNode((String)point.getKeys().get(j)));
					elemValue.appendChild(doc.createTextNode(" "));
					elemValue.appendChild(doc.createTextNode(String.valueOf((point.getValue((String)point.getKeys().get(j))))));
					elemValue.appendChild(doc.createTextNode(" "));
					elemPointModel.appendChild(elemValue);
				}
			}
			
			//Creating DOM element "PointsList"
			org.w3c.dom.Element elemPatchesList = doc.createElement("PatchesList");
			elemGeoPostpModel.appendChild(elemPatchesList);
			
			//Creating DOM elements "Patch"
			ListIterator patchesIT = geoPostpModel.getPatches().listIterator();
			while (patchesIT.hasNext()){
				patch = (Patch)patchesIT.next();
				org.w3c.dom.Element elemPatch = doc.createElement("Patch");
				elemPatch.setAttribute("label", "" + patch.getLabel());
				elemPatchesList.appendChild(elemPatch);
				
				//Creating DOM elements "patchPointsLabels"
				org.w3c.dom.Element elemPatchPointsLabels = doc.createElement("PatchPointsLabels");
				for(int i=0;i<patch.getPointsLabels().length;i++){
					elemPatchPointsLabels.appendChild(doc.createTextNode(patch.getPointsLabels()[i]));
					elemPatchPointsLabels.appendChild(doc.createTextNode(" "));
					elemPatch.appendChild(elemPatchPointsLabels);
				}
				
			}//End of creating DOM element "Patch"
			
			//Creating DOM element "BoundariesList"
			org.w3c.dom.Element elemBoundariesList = doc.createElement("BoundariesList");
			elemGeoPostpModel.appendChild(elemBoundariesList);
			
			//Creating DOM elements "Boundary"
			ListIterator boundariesIT = geoPostpModel.getBoundaries().listIterator();
			while (boundariesIT.hasNext()){
				boundary = (Boundary)boundariesIT.next();
				//Creating DOM element "Boundary"
				org.w3c.dom.Element elemBoundary = doc.createElement("Boundary");
				elemBoundary.setAttribute("label", "" + boundary.getLabel());
				elemBoundariesList.appendChild(elemBoundary);
				
				//Creating DOM elements "BoundPointsLabels"
				org.w3c.dom.Element elemBoundPointsLabels = doc.createElement("BoundPointsLabels");
				for(int i=0;i<boundary.getPointsLabels().length;i++){
					elemBoundPointsLabels.appendChild(doc.createTextNode(boundary.getPointsLabels()[i]));
					elemBoundPointsLabels.appendChild(doc.createTextNode(" "));
					elemBoundary.appendChild(elemBoundPointsLabels);
				}
				
			}//End of creating DOM element "Boundary"
			
		}
		
//		Creating DOM elements "stepAttributes"
		for(int j=0;j<stepPostp.getKeys().size();j++){
			org.w3c.dom.Element elemStepAttributes = doc.createElement("stepAttributes");
			elemStepAttributes.appendChild(doc.createTextNode((String)stepPostp.getKeys().get(j)));
			elemStepAttributes.appendChild(doc.createTextNode(" "));
			elemStepAttributes.appendChild(doc.createTextNode(String.valueOf(fmt.format(stepPostp.getStepValue((String)stepPostp.getKeys().get(j))))));
			elemStepAttributes.appendChild(doc.createTextNode(" "));
			elemStep.appendChild(elemStepAttributes);
		}
		
		docOutput = doc;
		// } //end of try 
		
//		catch (ParserConfigurationException pce){
//		System.out.println("Could not create DOM parser.");
//		System.out.println(pce.getMessage());
//		System.exit(4);
//		}
		
	}
	
	
	public void serializeDOMTreeIntoXMLDocument(String resultFile) {
		try {
			TransformerFactory tf = TransformerFactory.newInstance();
			tf.setAttribute("indent-number", new Integer(4));
			Transformer t = tf.newTransformer();
			t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "insane.dtd");
			t.setOutputProperty(OutputKeys.INDENT, "yes");
			t.setOutputProperty(OutputKeys.ENCODING, "ISO8859-1");
			t.transform(new DOMSource((Document) docOutput),new StreamResult(new FileWriter(resultFile)));
		} catch (TransformerException te) {
			System.out.println("Problem serializing DOM tree");
			System.out.println(te.getMessageAndLocation());
			System.exit(1);
		} catch (IOException e) {
			System.out.println("Problem serializing DOM tree");
			System.out.println(e.getLocalizedMessage());
			System.exit(1);
		}
	}
	
//	/** Serializes the DOM tree into a XML file.
//	 *@param resultFile The name of the output file.
//	 */
//	public void serializeDOMTreeIntoXMLDocument(String resultFile)
//	{
//		try
//		{
//			Transformer trans = TransformerFactory.newInstance().newTransformer();
//			trans.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "postp.dtd");
//			trans.setOutputProperty(OutputKeys.INDENT, "yes");
//			trans.setOutputProperty(OutputKeys.ENCODING, "ISO8859-1");
//			trans.setOutputProperty(OutputKeys.INDENT, "yes");
//			trans.transform(new DOMSource((Document) docOutput ), new StreamResult(resultFile));
//		} 
//		catch (TransformerException te)
//		{
//			System.out.println("Problem serializing DOM tree");
//			System.out.println(te.getMessageAndLocation());
//			System.exit(5);
//		}
//	}
}
